<template>
    <div class="cron-generator">
        <div class="cron-header">
            <h2>Cron表达式生成器</h2>
        </div>

        <div class="cron-body">
            <!-- 字段标签行 -->
            <div class="field-labels">
                <div class="field-label" :class="activeField == field.name ? 'ac' : ''" v-for="field in fields"
                    :key="field.name" @click="fieldsClick(field.name)">
                    {{ field.label }}
                </div>
            </div>

            <!-- 配置区域 -->
            <div class="config-section">
                <!-- 秒配置 -->
                <div class="field-config" v-show="activeField === 'second'">
                    <div class="config-options">
                        <label>
                            <input type="radio" v-model="secondConfig.type" value="every"> 每秒
                        </label>
                        <label>
                            <input type="radio" v-model="secondConfig.type" value="cycle"> 周期从
                            <input v-model="secondConfig.cycleFrom" type="number" min="0" max="59"> 到
                            <input v-model="secondConfig.cycleTo" type="number" min="0" max="59"> 秒
                        </label>
                        <label>
                            <input type="radio" v-model="secondConfig.type" value="interval"> 周期从
                            <input v-model="secondConfig.intervalFrom" type="number" min="0" max="59"> 秒开始，每
                            <input v-model="secondConfig.intervalStep" type="number" min="1" max="59"> 秒执行一次
                        </label>
                        <label>
                            <input type="radio" v-model="secondConfig.type" value="specific"> 指定
                        </label>
                    </div>
                    <div class="specific-options" v-if="secondConfig.type === 'specific'">
                        <button v-for="sec in 60" :key="sec - 1" class="number-btn"
                            :class="{ active: secondConfig.specific.includes((sec - 1).toString().padStart(2, '0')) }"
                            @click="toggleSpecific('second', (sec - 1).toString().padStart(2, '0'))">
                            {{ (sec - 1).toString().padStart(2, '0') }}
                        </button>
                    </div>
                </div>

                <!-- 分钟配置 -->
                <div class="field-config" v-show="activeField === 'minute'">
                    <div class="config-options">
                        <label>
                            <input type="radio" v-model="minuteConfig.type" value="every"> 每分钟
                        </label>
                        <label>
                            <input type="radio" v-model="minuteConfig.type" value="cycle"> 周期从
                            <input v-model="minuteConfig.cycleFrom" type="number" min="0" max="59"> 到
                            <input v-model="minuteConfig.cycleTo" type="number" min="0" max="59"> 分钟
                        </label>
                        <label>
                            <input type="radio" v-model="minuteConfig.type" value="interval"> 周期从
                            <input v-model="minuteConfig.intervalFrom" type="number" min="0" max="59"> 分钟开始，每
                            <input v-model="minuteConfig.intervalStep" type="number" min="1" max="59"> 分钟执行一次
                        </label>
                        <label>
                            <input type="radio" v-model="minuteConfig.type" value="specific"> 指定
                        </label>
                    </div>
                    <div class="specific-options" v-if="minuteConfig.type === 'specific'">
                        <button v-for="min in 60" :key="min - 1" class="number-btn"
                            :class="{ active: minuteConfig.specific.includes((min - 1).toString().padStart(2, '0')) }"
                            @click="toggleSpecific('minute', (min - 1).toString().padStart(2, '0'))">
                            {{ (min - 1).toString().padStart(2, '0') }}
                        </button>
                    </div>
                </div>

                <!-- 小时配置 -->
                <div class="field-config" v-show="activeField === 'hour'">
                    <div class="config-options">
                        <label>
                            <input type="radio" v-model="hourConfig.type" value="every"> 每小时
                        </label>
                        <label>
                            <input type="radio" v-model="hourConfig.type" value="cycle"> 周期从
                            <input v-model="hourConfig.cycleFrom" type="number" min="0" max="23"> 到
                            <input v-model="hourConfig.cycleTo" type="number" min="0" max="23"> 小时
                        </label>
                        <label>
                            <input type="radio" v-model="hourConfig.type" value="interval"> 周期从
                            <input v-model="hourConfig.intervalFrom" type="number" min="0" max="23"> 小时开始，每
                            <input v-model="hourConfig.intervalStep" type="number" min="1" max="23"> 小时执行一次
                        </label>
                        <label>
                            <input type="radio" v-model="hourConfig.type" value="specific"> 指定
                        </label>
                    </div>
                    <div class="specific-options" v-if="hourConfig.type === 'specific'">
                        <div class="am-pm-section">
                            <div class="time-period">上午：</div>
                            <button v-for="h in 12" :key="h - 1" class="number-btn"
                                :class="{ active: hourConfig.specific.includes((h - 1).toString().padStart(2, '0')) }"
                                @click="toggleSpecific('hour', (h - 1).toString().padStart(2, '0'))">
                                {{ (h - 1).toString().padStart(2, '0') }}
                            </button>
                        </div>
                        <div class="am-pm-section">
                            <div class="time-period">下午：</div>
                            <button v-for="h in 12" :key="h + 11" class="number-btn"
                                :class="{ active: hourConfig.specific.includes((h + 11).toString().padStart(2, '0')) }"
                                @click="toggleSpecific('hour', (h + 11).toString().padStart(2, '0'))">
                                {{ (h + 11).toString().padStart(2, '0') }}
                            </button>
                        </div>
                    </div>
                </div>

                <!-- 日配置 -->
                <div class="field-config" v-show="activeField === 'day'">
                    <div class="config-options">
                        <label>
                            <input type="radio" v-model="dayConfig.type" value="every"> 每日
                        </label>
                        <label>
                            <input type="radio" v-model="dayConfig.type" value="cycle"> 周期从
                            <input v-model="dayConfig.cycleFrom" type="number" min="1" max="31"> 到
                            <input v-model="dayConfig.cycleTo" type="number" min="1" max="31"> 日
                        </label>
                        <label>
                            <input type="radio" v-model="dayConfig.type" value="interval"> 周期从
                            <input v-model="dayConfig.intervalFrom" type="number" min="1" max="31"> 日开始，每
                            <input v-model="dayConfig.intervalStep" type="number" min="1" max="31"> 日执行一次
                        </label>
                        <label>
                            <input type="radio" v-model="dayConfig.type" value="workday"> 每月
                            <input v-model="dayConfig.workday" type="number" min="1" max="31"> 号最近的那个工作日
                        </label>
                        <label>
                            <input type="radio" v-model="dayConfig.type" value="last"> 本月最后一天
                        </label>
                        <label>
                            <input type="radio" v-model="dayConfig.type" value="specific"> 指定
                        </label>
                    </div>
                    <div class="specific-options" v-if="dayConfig.type === 'specific'">
                        <button v-for="day in 31" :key="day" class="number-btn"
                            :class="{ active: dayConfig.specific.includes(day.toString().padStart(2, '0')) }"
                            @click="toggleSpecific('day', day.toString().padStart(2, '0'))">
                            {{ day.toString().padStart(2, '0') }}
                        </button>
                    </div>
                </div>

                <!-- 月配置 -->
                <div class="field-config" v-show="activeField === 'month'">
                    <div class="config-options">
                        <label>
                            <input type="radio" v-model="monthConfig.type" value="every"> 每月
                        </label>
                        <label>
                            <input type="radio" v-model="monthConfig.type" value="cycle"> 周期从
                            <input v-model="monthConfig.cycleFrom" type="number" min="1" max="12"> 到
                            <input v-model="monthConfig.cycleTo" type="number" min="1" max="12"> 月
                        </label>
                        <label>
                            <input type="radio" v-model="monthConfig.type" value="interval"> 周期从
                            <input v-model="monthConfig.intervalFrom" type="number" min="1" max="12"> 月开始，每
                            <input v-model="monthConfig.intervalStep" type="number" min="1" max="12"> 月执行一次
                        </label>
                        <label>
                            <input type="radio" v-model="monthConfig.type" value="specific"> 指定
                        </label>
                    </div>
                    <div class="specific-options" v-if="monthConfig.type === 'specific'">
                        <button v-for="month in 12" :key="month" class="number-btn"
                            :class="{ active: monthConfig.specific.includes(month.toString().padStart(2, '0')) }"
                            @click="toggleSpecific('month', month.toString().padStart(2, '0'))">
                            {{ month.toString().padStart(2, '0') }}
                        </button>
                    </div>
                </div>

                <!-- 周配置 -->
                <div class="field-config" v-show="activeField === 'week'">
                    <div class="config-options">
                        <label>
                            <input type="radio" v-model="weekConfig.type" value="unspecified"> 不指定
                        </label>
                        <label>
                            <input type="radio" v-model="weekConfig.type" value="cycle"> 周期从星期
                            <input v-model="weekConfig.cycleFrom" type="number" min="1" max="7"> 到星期
                            <input v-model="weekConfig.cycleTo" type="number" min="1" max="7">
                        </label>
                        <label>
                            <input type="radio" v-model="weekConfig.type" value="nth"> 第
                            <input v-model="weekConfig.nthWeek" type="number" min="1" max="5"> 周的星期
                            <input v-model="weekConfig.nthDay" type="number" min="1" max="7">
                        </label>
                        <label>
                            <input type="radio" v-model="weekConfig.type" value="last"> 本月最后一个星期
                            <input v-model="weekConfig.lastDay" type="number" min="1" max="7">
                        </label>
                        <label>
                            <input type="radio" v-model="weekConfig.type" value="specific"> 指定
                        </label>
                    </div>
                    <div class="specific-options" v-if="weekConfig.type === 'specific'">
                        <button v-for="day in 7" :key="day" class="number-btn"
                            :class="{ active: weekConfig.specific.includes(day.toString()) }"
                            @click="toggleSpecific('week', day.toString())">
                            星期{{ ['日', '一', '二', '三', '四', '五', '六'][day - 1] }}
                        </button>
                    </div>
                </div>

                <!-- 年配置 -->
                <div class="field-config" v-show="activeField === 'year'">
                    <div class="config-options">
                        <label>
                            <input type="radio" v-model="yearConfig.type" value="unspecified"> 不指定
                        </label>
                        <label>
                            <input type="radio" v-model="yearConfig.type" value="cycle"> 周期从
                            <input v-model="yearConfig.cycleFrom" type="number" min="1970" max="2099"> 到
                            <input v-model="yearConfig.cycleTo" type="number" min="1970" max="2099"> 年
                        </label>
                    </div>
                </div>
            </div>

            <!-- 表达式显示区域 -->
            <div class="expression-section">
                <div class="expression-header">
                    <h3>&lt;/&gt; 表达式</h3>
                </div>

                <div class="expression-table">
                    <table>
                        <thead>
                            <tr>
                                <th v-for="field in fields" :key="field.name">{{ field.label }}</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td v-for="field in fields" :key="field.name">
                                    <span class="field-value">{{ getFieldValue(field.name) }}</span>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>

                <div class="cron-result">
                    <div class="cron-expression-display">
                        <strong>Cron表达式：</strong>
                        <code class="cron-string">{{ generatedCron }}</code>
                    </div>
                    <div class="error-message" v-if="errorMessage">
                        {{ errorMessage }}
                    </div>
                    <div class="action-buttons">
                        <button class="btn-primary" @click="generateCron">生成表达式</button>
                        <button class="btn-secondary" @click="parseCron">反解析</button>
                        <button class="btn-copy" @click="copyCron">复制</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
  
<script>
export default {
    name: 'CronGenerator',
    data() {
        return {
            activeField: 'second',

            fields: [
                { name: 'second', label: '秒' },
                { name: 'minute', label: '分钟' },
                { name: 'hour', label: '小时' },
                { name: 'day', label: '日' },
                { name: 'month', label: '月' },
                { name: 'week', label: '周' },
                { name: 'year', label: '年' }
            ],
            secondConfig: {
                type: 'specific',
                cycleFrom: 1,
                cycleTo: 2,
                intervalFrom: 0,
                intervalStep: 1,
                specific: ['00'] // 默认选中00秒
            },
            minuteConfig: {
                type: 'interval',
                cycleFrom: 1,
                cycleTo: 2,
                intervalFrom: 0,
                intervalStep: 1,
                specific: []
            },
            hourConfig: {
                type: 'every',
                cycleFrom: 0,
                cycleTo: 2,
                intervalFrom: 0,
                intervalStep: 1,
                specific: []
            },
            dayConfig: {
                type: 'every',
                cycleFrom: 1,
                cycleTo: 2,
                intervalFrom: 1,
                intervalStep: 1,
                workday: 1,
                specific: []
            },
            monthConfig: {
                type: 'every',
                cycleFrom: 1,
                cycleTo: 2,
                intervalFrom: 1,
                intervalStep: 1,
                specific: []
            },
            weekConfig: {
                type: 'unspecified',
                cycleFrom: 1,
                cycleTo: 2,
                nthWeek: 1,
                nthDay: 1,
                lastDay: 1,
                specific: []
            },
            yearConfig: {
                type: 'unspecified',
                cycleFrom: 2018,
                cycleTo: 2019
            },
            generatedCron: '* * * * * ? *',
            errorMessage: ''
        }
    },
    methods: {
        fieldsClick(name) {
            console.log('fieldsClick', name);
            this.activeField = name
        },
        toggleSpecific(field, value) {
            console.log('toggleSpecific', field);
            const config = this[`${field}Config`]
            const index = config.specific.indexOf(value)
            if (index > -1) {
                config.specific.splice(index, 1)
            } else {
                config.specific.push(value)
            }
        },

        getFieldValue(field) {
            const config = this[`${field}Config`];
            console.log('field', field, config.type);
            // 处理数字前导零的工具函数
            const formatNumber = (numStr) => {
                const num = parseInt(numStr, 10);
                return isNaN(num) ? numStr : num.toString();
            };

            switch (config.type) {
                case 'every':
                    return '*'; // 所有every类型统一返回*
                case 'cycle':
                    return `${formatNumber(config.cycleFrom.toString())}-${formatNumber(config.cycleTo.toString())}`;
                case 'interval':
                    if (field === 'minute' && config.intervalFrom === 0 && config.intervalStep === 1) {
                        return '*';
                    }
                    return `${formatNumber(config.intervalFrom.toString())}/${formatNumber(config.intervalStep.toString())}`;
                case 'specific':
                    if (config.specific.length === 0) return '*';
                    // 处理特定值的前导零
                    const formatted = config.specific.map(v => formatNumber(v));
                    return formatted.join(',');
                case 'workday':
                    return `${formatNumber(config.workday.toString())}W`;
                case 'last':
                    return 'L';
                case 'nth':
                    return `${formatNumber(config.nthDay.toString())}#${formatNumber(config.nthWeek.toString())}`;
                case 'unspecified':
                    if (field === 'week') return '?';
                    if (field === 'year') return '';
                    return '*';
                default:
                    return '*';
            }
        },

        generateCron() {
            console.log('generateCron');
            try {
                const cronParts = this.fields.map(field => {
                    const value = this.getFieldValue(field.name)
                    return value
                }).filter(value => value !== '') // 过滤掉空值（年字段）

                this.generatedCron = cronParts.join(' ')
                this.errorMessage = ''

                // 验证日和周的冲突
                const dayIndex = this.fields.findIndex(f => f.name === 'day')
                const weekIndex = this.fields.findIndex(f => f.name === 'week')
                const dayValue = cronParts[dayIndex]
                const weekValue = cronParts[weekIndex]

                if (dayValue !== '?' && weekValue !== '?') {
                    this.errorMessage = '日和周不能同时指定具体值，其中一个必须为?'
                }
            } catch (error) {
                this.errorMessage = '生成表达式时出现错误'
            }
        },

        parseCron() {
            // 反解析功能实现
            alert('反解析功能待实现')
        },

        copyCron() {
            navigator.clipboard.writeText(this.generatedCron).then(() => {
                alert('Cron表达式已复制到剪贴板')
            })
        }
    },

    mounted() {
        this.generateCron()
    }
}
</script>
  
<style scoped>
.cron-generator {
    max-width: 1200px;
    margin: 0 auto;
    font-family: Arial, sans-serif;
}

.cron-header {
    background: #f5f5f5;
    padding: 20px;
    border-bottom: 1px solid #ddd;
}

.cron-body {
    padding: 20px;
}

.field-labels {
    display: flex;
    background: #e8f4fd;
    border: 1px solid #b8daff;
    margin-bottom: 20px;
}

.field-label {
    flex: 1;
    padding: 10px;
    text-align: center;
    font-weight: bold;
    border-right: 1px solid #b8daff;
    cursor: pointer;
}

.field-label.ac {
    background: #ff0;
}

.field-label:hover {
    background: #d1ecf1;
}

.field-label:last-child {
    border-right: none;
}

.config-section {
    border: 1px solid #ddd;
    padding: 20px;
    margin-bottom: 20px;
    min-height: 200px;
}

.config-options {
    margin-bottom: 15px;
}

.config-options label {
    display: block;
    margin-bottom: 8px;
    cursor: pointer;
}

.config-options input[type="radio"] {
    margin-right: 8px;
}

.config-options input[type="number"] {
    width: 60px;
    margin: 0 5px;
    padding: 2px 5px;
}

.specific-options {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    max-height: 150px;
    overflow-y: auto;
}

.number-btn {
    padding: 5px 10px;
    border: 1px solid #ccc;
    background: white;
    cursor: pointer;
    border-radius: 3px;
}

.number-btn:hover {
    background: #f0f0f0;
}

.number-btn.active {
    background: #007bff;
    color: white;
    border-color: #007bff;
}

.am-pm-section {
    width: 100%;
    margin-bottom: 10px;
}

.time-period {
    font-weight: bold;
    margin-bottom: 5px;
}

.expression-section {
    border: 1px solid #ddd;
    padding: 20px;
}

.expression-header {
    margin-bottom: 15px;
}

.expression-table table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 20px;
}

.expression-table th,
.expression-table td {
    border: 1px solid #ddd;
    padding: 10px;
    text-align: center;
}

.expression-table th {
    background: #f8f9fa;
    font-weight: bold;
}

.field-value {
    font-family: 'Courier New', monospace;
    font-weight: bold;
}

.cron-result {
    background: #f8f9fa;
    padding: 15px;
    border-radius: 5px;
}

.cron-expression-display {
    margin-bottom: 10px;
}

.cron-string {
    background: #e9ecef;
    padding: 5px 10px;
    border-radius: 3px;
    font-family: 'Courier New', monospace;
}

.error-message {
    color: #dc3545;
    margin-bottom: 10px;
    font-weight: bold;
}

.action-buttons {
    display: flex;
    gap: 10px;
}

.btn-primary,
.btn-secondary,
.btn-copy {
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

.btn-primary {
    background: #007bff;
    color: white;
}

.btn-secondary {
    background: #6c757d;
    color: white;
}

.btn-copy {
    background: #28a745;
    color: white;
}

.btn-primary:hover {
    background: #0056b3;
}

.btn-secondary:hover {
    background: #545b62;
}

.btn-copy:hover {
    background: #218838;
}
</style>